﻿/**	\file		lxmem_pool.hxx
 *	\date		(2014-11-18 23:43:06)/(2014-11-30 03:06:49)
 *-----------------------------------------------------------------------------
 *	\brief
 *	\version	1.0.0.2
 *	\author		Nick Shallery	(nicknide@gmail.com)
 *	\copyright	YOU HAVE ALL LEFT WITH THIS CODE WHILE YOU KEEP COMMENT IN EVERY COPY.
 *-----------------------------------------------------------------------------
**/

#if			!defined(__LOLIX__LX_MEM__POOL__HXX__NICK__K_IN_G__)
#define		__LOLIX__LX_MEM__POOL__HXX__NICK__K_IN_G__

#if			!defined(__LOLIX__LOLI_X_MACRO__K_IN_G__)
	#include	<lolix/lolix_macro.h>
#endif	//	!defined(__LOLIX__LOLI_X_MACRO__K_IN_G__)

#if			!defined(__LOLIX__LOLIX_TYPE__K_IN_G__)
	#include	<lolix/lolix_type.h>
#endif	//	!defined(__LOLIX__LOLIX_TYPE__K_IN_G__)

#if			!defined(__LOLIX_IMP__LOLIX_LOCK_OPT__H__NICK__K_IN_G__)
	#include	<lolix/imp/lolix_lock_opt.h>
#endif	//	!defined(__LOLIX_IMP__LOLIX_LOCK_OPT__H__NICK__K_IN_G__)

namespace lxpref{namespace _inst{
	namespace _help
	{
	template<typename _TyDat>
	struct _DatCnt
		: public _TyDat
	{
		_DatCnt* _datCntNextPtr;
	};
	}

	template<typename _TyDat, typename _TyAlc>
	class MemPool
	{
		typedef _help::_DatCnt<_TyDat> _DatType;
		typedef typename _TyAlc::template rebind<_TyDat>::other _TyDatAlc;
		typedef MemPool<_TyDat, _TyAlc> this_type;
		_DatType* _hNode;	//	header node.
		//lolix::size_type _lk;
		typename _TyAlc::template rebind<_DatType>::other _alc;

		void operator = (this_type const&);
	public:
		typedef _TyDatAlc allocator_type;
		typedef typename _TyDatAlc::const_pointer	const_pointer;
		typedef typename _TyDatAlc::const_reference	const_reference;
		typedef typename _TyDatAlc::pointer			pointer;
		typedef typename _TyDatAlc::reference		reference;
		typedef typename _TyDatAlc::size_type		size_type;
		typedef typename _TyDatAlc::value_type		value_type;

		template<typename _TyOther>
		struct rebind{typedef MemPool<_TyOther, typename _TyAlc::template rebind<_TyOther>::other> other;};

		LOLIX_INLINE_CALL MemPool(void)/*:_lk(0)*/{}
		template<typename _TyOtherAlc>
		LOLIX_INLINE_CALL explicit MemPool(_TyOtherAlc const& alc):_hNode(0), _alc(alc)/*, _lk(0)*/{}
		LOLIX_INLINE_CALL explicit MemPool(_TyAlc const& alc):_hNode(0), _alc(alc)/*, _lk(0)*/{}
		LOLIX_INLINE_CALL MemPool(this_type const& o) : _hNode(0), _alc(o._alc)/*, _lk(0)*/{}
		LOLIX_INLINE_CALL ~MemPool(void)
		{
			while ( _hNode )
			{
				auto cur = _hNode;
				_hNode = _hNode->_datCntNextPtr;
				_alc.destroy(cur);
				_alc.deallocate(cur, 1);
			}
		}

		LOLIX_INLINE_CALL pointer allocate(lolix::size_type cnt)
		{
			if ( cnt != 1 )
				return 0;

			if ( !_hNode )
				return this->__Fill_node(KB(1));

			_DatType* next;
			_DatType* cur;
			do
			{
				cur = _hNode;
				if ( !cur )
					return this->__Fill_node(KB(1));
				next = cur->_datCntNextPtr;
			} while ( lolix::imp::lock_cchg(&_hNode, next, cur) != cur );

			return cur;
		}


		LOLIX_INLINE_CALL void construct(pointer ptr)
		{
			_DatType* dat = (_DatType*)ptr;
			this->_alc.construct(dat);
			dat->_datCntNextPtr = 0;
			return;
		}

		LOLIX_INLINE_CALL void destroy(pointer ptr)
		{
			this->_alc.destroy((_DatType*)ptr);
		}

		LOLIX_INLINE_CALL void deallocate(pointer ptr, lolix::size_type cnt)
		{
			_DatType* dat = (_DatType*)ptr;
			_DatType* next;
			do
			{
				dat->_datCntNextPtr = next = this->_hNode;
			}while(lolix::imp::lock_cchg(&this->_hNode, dat, next) != next);
		}

	public:
		LOLIX_INLINE_CALL pointer __Fill_node(size_type cnt)
		{
			_DatType* rtv = this->_alc.allocate(1);
			--cnt;

			_DatType* dat = this->_alc.allocate(1);
			--cnt;
			_DatType* c = dat;
			while ( cnt )
			{
				auto n = this->_alc.allocate(1);
				--cnt;
				c->_datCntNextPtr = n;
				c = n;
			}
			_DatType* next;
			do
			{
				c->_datCntNextPtr = next = this->_hNode;
			}while(lolix::imp::lock_cchg(&this->_hNode, dat, next) != next);
			return rtv;
		}
	};
}}

#endif	//	!defined(__LOLIX__LX_MEM__POOL__HXX__NICK__K_IN_G__)
